package com.gxc.service.impl;

import com.gxc.dao.UserRepository;
import com.gxc.dto.AddUserParamsDto;
import com.gxc.dto.FindAllUserParamsDto;
import com.gxc.entity.User;
import com.gxc.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.validator.HibernateValidator;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;
import javax.validation.*;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author GongXincheng
 * @since 2019-08-08 14:56
 */
@Service
@Transactional(rollbackOn = Exception.class)
public class UserServiceImpl implements UserService {

    @Resource
    private UserRepository userRepository;
    @Resource
    private RedisTemplate<Integer, User> redisTemplate;

    @Resource
    private ValidatorFactory validatorFactory;

    @Resource
    private Validator validator;

    @Override
    public Boolean addTestUser(List<User> userList) {
        List<User> dbList = userRepository.saveAll(userList);
        return dbList != null && dbList.size() != 0;
    }

    @Override
    public User addUser(AddUserParamsDto paramsDto) {
        User user = new User();
        BeanUtils.copyProperties(paramsDto, user);
        return userRepository.save(user);
    }

    @Override
    public User findById(Integer id) {
        ValueOperations<Integer, User> opsForValue = redisTemplate.opsForValue();
        User user = opsForValue.get(id);
        if (user == null) {
            synchronized (this) {
                if (user == null) {
                    Optional<User> optional = userRepository.findById(id);
                    user = optional.orElse(null);
                    if (user != null) {
                        opsForValue.set(id, user, 30L, TimeUnit.SECONDS);
                    }
                }
            }
        }
        return user;
    }


    @Override
    public Page<User> findAll(FindAllUserParamsDto paramsDto) {
        Pageable pageable = PageRequest.of(paramsDto.getPageNum() - 1, paramsDto.getPageSize());
        return userRepository.findAll((Specification<User>) (root, query, criteriaBuilder) -> {
            List<Predicate> predicateList = new ArrayList<>(5);
            if (StringUtils.isNotBlank(paramsDto.getUsername())) {
                predicateList.add(criteriaBuilder.like(root.get("username"), "%" + paramsDto.getUsername() + "%"));
            }
            if (StringUtils.isNotBlank(paramsDto.getPassword())) {
                predicateList.add(criteriaBuilder.equal(root.get("password"), paramsDto.getPassword()));
            }
            if (paramsDto.getAge() != null && paramsDto.getAge() >= 0) {
                predicateList.add(criteriaBuilder.equal(root.get("age"), paramsDto.getAge()));
            }
            if (StringUtils.isNotBlank(paramsDto.getDescription())) {
                predicateList.add(criteriaBuilder.like(root.get("description"), "%" + paramsDto.getDescription() + "%"));
            }
            query.where(criteriaBuilder.and(predicateList.toArray(new Predicate[]{})));
            query.orderBy(criteriaBuilder.desc(root.get("id")));
            return query.getRestriction();
        }, pageable);
    }

    @Override
    public Object validToService(AddUserParamsDto dto) {
        List<String> list = new ArrayList<>();

        // Validator validator = validatorFactory.getValidator();
        Set<ConstraintViolation<AddUserParamsDto>> violations = validator.validate(dto);
        // 循环set
        for (ConstraintViolation<AddUserParamsDto> violation : violations) {
            list.add(violation.getMessage());
        }
        return list;
    }
}
